
import mxgraph from 'pages/mxgraph/graph/index';

import graphUtil from "pages/mxgraph/graphUtil";
import canvasUtil from './canvasUtil';
import { behaviors } from 'src/pages/mxgraph/behaviors/index';
import { GraphShapeUtil } from '@/pages/mxgraph/GraphShapeUtil';

const {
  mxConstants,
  mxGraphHandler,
  mxEvent,
  mxUtils,
  mxCellHighlight,
  mxEdgeHandler,
  mxConnectionConstraint
} = mxgraph;
/**
 * Function: mouseMove
 *
 * Handles the event by highlighting possible drop targets and updating the
 * preview.
 */
mxGraphHandler.prototype.mouseMove = function(sender, me)
{
  let graph = this.graph;

  if (!me.isConsumed() && graph.isMouseDown && this.cell != null &&
		this.first != null && this.bounds != null && !this.suspended)
  {
    //// Stops moving if a multi touch event is received
    if (mxEvent.isMultiTouchEvent(me.getEvent()))
    {
      this.reset();
      return;
    }

    let delta = this.getDelta(me);
    let tol = graph.tolerance;

    if (this.shape != null || this.livePreviewActive || Math.abs(delta.x) > tol || Math.abs(delta.y) > tol)
    {
      //// Highlight is used for highlighting drop targets
      if (this.highlight == null)
      {
        this.highlight = new mxCellHighlight(this.graph,
          mxConstants.DROP_TARGET_COLOR, 3);
      }

      let clone = graph.isCloneEvent(me.getEvent()) && graph.isCellsCloneable() && this.isCloneEnabled();
      let gridEnabled = graph.isGridEnabledEvent(me.getEvent());
      let cell = me.getCell();
      let hideGuide = true;
      let target = null;
      this.cloning = clone;
      //// console.log('mouse move', this.cells, cell, me);

      if (graph.isDropEnabled() && this.highlightEnabled)
      {
        //// Contains a call to getCellAt to find the cell under the mouse
        target = graph.getDropTarget(this.cells, me.getEvent(), cell, clone);
      }

      let state = graph.getView().getState(target);
      let highlight = false;

      if (state != null && (clone || this.isValidDropTarget(target, me)))
      {
			  if (this.target != target){
				  this.target = target;
				  this.setHighlightColor(mxConstants.DROP_TARGET_COLOR);
        }

        ////  如果parent相同则不显示高亮
			  if (this.target !== this.cell.parent){
          highlight = true;

        }

      }
      else
      {
        this.target = null;

        if (this.connectOnDrop && cell != null && this.cells.length == 1 &&
					graph.getModel().isVertex(cell) && graph.isCellConnectable(cell))
        {
          state = graph.getView().getState(cell);

          if (state != null)
          {
            let error = graph.getEdgeValidationError(null, this.cell, cell);
            let color = (error == null) ?
              mxConstants.VALID_COLOR :
              mxConstants.INVALID_CONNECT_TARGET_COLOR;
            this.setHighlightColor(color);
            highlight = true;
          }
        }
      }

      if (state != null && highlight)
      {
        this.highlight.highlight(state);
      }
      else
      {
        this.highlight.hide();
      }

      if (this.guide != null && this.useGuidesForEvent(me))
      {
        delta = this.guide.move(this.bounds, delta, gridEnabled, clone);
        hideGuide = false;
      }
      else
      {
        delta = this.graph.snapDelta(delta, this.bounds, !gridEnabled, false, false);
      }

      if (this.guide != null && hideGuide)
      {
        this.guide.hide();
      }

      //// Constrained movement if shift key is pressed
      if (graph.isConstrainedEvent(me.getEvent()))
      {
        if (Math.abs(delta.x) > Math.abs(delta.y))
        {
          delta.y = 0;
        }
        else
        {
          delta.x = 0;
        }
      }

      this.checkPreview();

      if (this.currentDx != delta.x || this.currentDy != delta.y)
      {
        this.currentDx = delta.x;
        this.currentDy = delta.y;
        this.updatePreview();
      }
    }

    this.updateHint(me);
    this.consumeMouseEvent(mxEvent.MOUSE_MOVE, me);

    //// Cancels the bubbling of events to the container so
    //// that the droptarget is not reset due to an mouseMove
    //// fired on the container with no associated state.
    mxEvent.consume(me.getEvent());
  }
  else if ((this.isMoveEnabled() || this.isCloneEnabled()) && this.updateCursor && !me.isConsumed() &&
			(me.getState() != null || me.sourceState != null) && !graph.isMouseDown)
  {
    let cursor = graph.getCursorForMouseEvent(me);

    if (cursor == null && graph.isEnabled() && graph.isCellMovable(me.getCell()))
    {
      if (graph.getModel().isEdge(me.getCell()))
      {
        cursor = mxConstants.CURSOR_MOVABLE_EDGE;
      }
      else
      {
        cursor = mxConstants.CURSOR_MOVABLE_VERTEX;
      }
    }

    //// Sets the cursor on the original source state under the mouse
    //// instead of the event source state which can be the parent
    if (cursor != null && me.sourceState != null)
    {
      me.sourceState.setCursor(cursor);
    }
  }
};

const updatePreview = mxGraphHandler.prototype.updatePreview;

//// 移动元素时更新预览框的位置
mxGraphHandler.prototype.updatePreview = function(remote)
{
  const style = this.cell && this.graph.view.getState(this.cell).style;
  if (style){
    if (style.xonly){
      this.currentDy = 0;

    } else if (style.yonly){
      this.currentDx = 0;

    }
  }
  updatePreview.apply(this, arguments);
};

//// 触发事件时获取事件的cell，此处对触发事件的cell进行了重定向，使得事件首次只会触发在mainCell上
mxGraphHandler.prototype.getInitialCellForEvent = function(me){
  let state = me.getState();

  if ((!this.graph.isToggleEvent(me.getEvent()) || !mxEvent.isAltDown(me.getEvent())) &&
		state != null && !this.graph.isCellSelected(state.cell))
  {
    let model = this.graph.model;
    let next = this.graph.view.getState(model.getParent(state.cell));
    //// 增加了判断 如果是mainCell 直接return
    if (graphUtil.isMainShape(state.cell.umlShape) || this.graph.isCellMovable(state.cell)) return state.cell;

    while (next != null && !this.graph.isCellSelected(next.cell) &&
			(model.isVertex(next.cell) || model.isEdge(next.cell)) &&
			this.isPropagateSelectionCell(state.cell, true, me))
    {

      state = next;
      //// 增加了判断 如果是mainCell 停止向上查询

      if (graphUtil.isMainShape(state.cell.umlShape) || this.graph.isCellMovable(state.cell)) break;
      next = this.graph.view.getState(this.graph.getModel().getParent(state.cell));
    }
  }

  return (state != null) ? state.cell : null;
};

//// Selection is delayed to mouseup if ancestor is selected
//// 默认是鼠标按下时选中，如果此方法返回true则则会延迟到鼠标抬起时才选中，deep是1的元素不延迟选中
let graphHandlerIsDelayedSelection = mxGraphHandler.prototype.isDelayedSelection;
mxGraphHandler.prototype.isDelayedSelection = function (cell, me) {
  const cells = this.graph.selectionModel.cells;
  if (cells.length > 1 ) return true;  //// 如果处于多选状态则延迟选择，否拖拽不了多个元素
  return false;
  //// let result = graphHandlerIsDelayedSelection.apply(this, arguments);
  //// if (cell.deep === 1) return false; //// deep是1的元素不延迟选中

  //// if (!result) {
  ////   let model = this.graph.getModel();
  ////   let parent = model.getParent(cell);

  ////   while (parent != null) {
  ////     //// Inconsistency for unselected parent swimlane is intended for easier moving
  ////     //// of stack layouts where the container title section is too far away
  ////     if (this.graph.isCellSelected(parent) && model.isVertex(parent)) {
  ////       result = true;
  ////       break;
  ////     }

  ////     parent = model.getParent(parent);
  ////   }
  //// }

  //// return result;
};

//// 移动cell时检查是否可以drop到目标cell，用于高亮目标cell
mxGraphHandler.prototype.isValidDropTarget = function(target, me)
{
  //// console.log('111111');
  //// 类型检查 ，自己不能放到自己里， parent不能放到children里
  return graphUtil.isValidDropTarget(this.graph, this.cells, target);

  //// return shapeApi.checkNest(this.cell.typeName, target.typeName) && this.cell.id !== target.id &&  !this.graph.model.isAncestor(this.cell, target, );
};

//// 移动cell时，如果没有目标cell则以diagram cell为目标cell
let mxGraphHandlerMoveCells = mxGraphHandler.prototype.moveCells;
const keepParentPositions = [ 'port', 'movableLabel', 'edgeLabel', 'edge'];
const isShapeKeepParent = (shape) => {
  if (shape.getTypeName() === 'ActivityParameterNode' && shape.box.position == 'port' ) return false;
  return keepParentPositions.includes(shape.box.position);
};
mxGraphHandler.prototype.moveCells = function (cells, dx, dy, clone, target, evt) {
  //// 如果target是null有可能是不能改变父子关系，也有可能是拖到diagram外面了
  console.log('move cells', cells, target, dx, dy, evt);
  let isOut = false;
  if (evt.state === null){
    isOut = true;
  }

  //// 过滤掉children cell，只处理parent
  const ansCells = cells.filter(cell => {
    return !cells.find(ans => {
      return graphUtil.isAncestor(ans, cell);
    });
  });

  if (target == null){ //// 如果target是null有可能是不能改变父子关系，也有可能是拖到diagram外面了
 
    ansCells.forEach(cell => {
      //// keepParentCells.push(cell);
      mxGraphHandlerMoveCells.apply(this, [[cell], dx, dy, clone, cell.parent, evt]);

    });

  } else { //// 拖到了目标元素上
    //// console.log('drag to target shape');
    ansCells.forEach(cell => {
      if (isShapeKeepParent(cell.umlShape) ){ //// 此类元素不会变更父子关系
        //// keepParentCells.push(cell);
        mxGraphHandlerMoveCells.apply(this, [[cell], dx, dy, clone, cell.parent, evt]);
      } else {
        //// changeParentCells.push(cell);
        const result = behaviors.get(target.umlShape.getTypeName()).shapeDrop(cell.umlShape, target.umlShape, this.graph.diagramNode, evt);
        result && mxGraphHandlerMoveCells.apply(this, [[cell], dx, dy, clone, target, evt]);

      }
    });

  }

};

/**
 * drop流程
 * 1. 鼠标move触发 mxGraph.getDropTarget
 * 2. mxGraphHandler.isValidDropTarget验证并高亮目标cell
 * 3. 抬起鼠标时触发mxGraphHandler.moveCells , moveCells方法中传入的就是第1步中获得的target
 */

mxGraphHandler.prototype.mouseDown = function(sender, me)
{
  if (!me.isConsumed() && this.isEnabled() && this.graph.isEnabled() &&
		me.getState() != null && !mxEvent.isMultiTouchEvent(me.getEvent()))
  {
    let cell = this.getInitialCellForEvent(me);
    this.delayedSelection = this.isDelayedSelection(cell, me);
    this.cell = null;

    if (this.isSelectEnabled() && !this.delayedSelection)
    {
      this.graph.selectCellForEvent(cell, me.getEvent());
    }

    if (this.isMoveEnabled())
    {

      while (!this.graph.isCellMovable(cell) && cell.deep > 1){
        cell = cell.parent;
      }
      //// return;
      console.log('move start');

      let model = this.graph.model;
      let geo = model.getGeometry(cell);

      if (this.graph.isCellMovable(cell) && ((!model.isEdge(cell) || this.graph.getSelectionCount() > 1 ||
        (geo.points != null && geo.points.length > 0) || model.getTerminal(cell, true) == null ||
        model.getTerminal(cell, false) == null) || this.graph.allowDanglingEdges ||
        (this.graph.isCloneEvent(me.getEvent()) && this.graph.isCellsCloneable()))) {
        console.log('start-----');
        this.start(cell, me.getX(), me.getY());
      } else if (this.delayedSelection) {
        this.cell = cell;
      }

      this.cellWasClicked = true;
      this.consumeMouseEvent(mxEvent.MOUSE_DOWN, me);
    }
  } else { //// 右键也可以选中
    let cell = this.getInitialCellForEvent(me);
    this.delayedSelection = this.isDelayedSelection(cell, me);
    if (this.isSelectEnabled() && !this.delayedSelection)
    {
      this.graph.selectCellForEvent(cell, me.getEvent());
    }
  }
};
/**
     * Updates the hint for the current operation.
     */
mxGraphHandler.prototype.updateHint = function (me) {
  //// console.log(4545454545);

  if (this.shape != null) {
    if (this.hint == null) {
      this.hint = canvasUtil.createHint();
      this.graph.container.appendChild(this.hint);
    }

    let t = this.graph.view.translate;
    let s = this.graph.view.scale;
    let x = this.roundLength((this.bounds.x + this.currentDx) / s - t.x);
    let y = this.roundLength((this.bounds.y + this.currentDy) / s - t.y);
    let unit = this.graph.view.unit;

    this.hint.innerHTML = canvasUtil.formatHintText(x, unit) + ", " + canvasUtil.formatHintText(y, unit);

    this.hint.style.left =
          this.shape.bounds.x +
          Math.round((this.shape.bounds.width - this.hint.clientWidth) / 2) +
          "px";
    this.hint.style.top =
          this.shape.bounds.y + this.shape.bounds.height + 12 + "px";
  }
};
/**
     * Function: mouseUp
     *
     * Handles the event by applying the changes to the selection cells.
     */
mxGraphHandler.prototype.mouseUp = function (sender, me) {
  if (!me.isConsumed()) {
    if (this.livePreviewUsed) {
      this.resetLivePreview();
    }

    if (this.cell != null && this.first != null && (this.shape != null || this.livePreviewUsed) &&
          this.currentDx != null && this.currentDy != null) {
      let graph = this.graph;
      let cell = me.getCell();

      if (this.connectOnDrop && this.target == null && cell != null && graph.getModel().isVertex(cell) &&
            graph.isCellConnectable(cell) && graph.isEdgeValid(null, this.cell, cell)) {
        graph.connectionHandler.connect(this.cell, cell, me.getEvent());
      } else {
        let clone = graph.isCloneEvent(me.getEvent()) && graph.isCellsCloneable() && this.isCloneEnabled();
        let scale = graph.getView().scale;
        let dx = this.roundLength(this.currentDx / scale);
        let dy = this.roundLength(this.currentDy / scale);
        let target = this.target;

        //// this.printParent = null;
        //// this.printMe = null;
        //// this.positionObj = null
        if (graph.isSplitEnabled() && graph.isSplitTarget(target, this.cells, me.getEvent())) {
          graph.splitEdge(target, this.cells, null, dx, dy);
        } else {

          if (this.cells.length > 0){

            if (mxUtils.getValue(graph.view.getState(graph.getSelectionCell()).style, "xonly", "0") == 1) {
              dy = 0;
            }

            if ( mxUtils.getValue(graph.view.getState(graph.getSelectionCell()).style, "yonly", "0") == 1) {
              console.log('限制message X轴移动');
              dx = 0;
            }
          }
          //// const sourcePoint = this.cells[0].geometry.getPoint();
          //// const terminalPoint = this.cells[0].geometry.getTerminalPoint();
          //// //// const points = 
          //// console.log('mmmmmmmmmmmmmmmmmmm', this.cells[0].geometry.getPoint(), sourcePoint, terminalPoint);
          
          this.moveCells(this.cells, dx, dy, clone, this.target, me.getEvent());
          console.log('moveCells');
          this.updatePoints(this.cells);
          //// debugger;
        }
      }
    } else if (this.isSelectEnabled() && this.delayedSelection && this.cell != null) {
      this.selectDelayed(me);
      this.graph.selectCellForEvent(this.cell, me.getEvent());
    }
  }

  //// Consumes the event if a cell was initially clicked
  if (this.cellWasClicked) {
    this.consumeMouseEvent(mxEvent.MOUSE_UP, me);
  }

  this.reset();
};

//// 发生线段交叉，重置points
mxGraphHandler.prototype.updatePoints = function (cells) {
  //// console.log('current cells', cells);
  //// console.log('graph', this.graph);
  const mxGraphView = this.graph.getView();
  //// console.log('view', this.graph.getView()); 
  cells.forEach(cell => {
    const edges = this.graph.getEdges(cell);
    console.log('edges', edges);
    edges.forEach(edge => {
      const edgeState = mxGraphView.getState(edge);
      if (!edgeState || !edgeState.absolutePoints) return;
      const points = [...edgeState.absolutePoints];
      //// this.setTargetTerminalPoint(edge, edgeState, points);
      const intersecPointIndex = this.getIntersecPointIndex(points);
      console.log('edgeState', edgeState, edgeState.absolutePoints);
      //// console.log('points', points);
      //// console.log('intersecPointIndex', intersecPointIndex);
      if (intersecPointIndex < points.length - 1) { //// 表示有线段相交
        //// console.log('resetedge');
        this.graph.resetEdge(edge);
        GraphShapeUtil.updateWaypoints(edge.umlShape, []);
      }
    });
  });
  
};

//// 改变终点，尽可能的不出现折弯
mxGraphHandler.prototype.setTargetTerminalPoint = function (edge, edgeState, points) {
  const sourcePoint = points[0];
  const targetPoint = points[points.length - 1];
  const target = edge.target.geometry;
  const sourceY = sourcePoint.y;
  const targetY = targetPoint.y;
  const minY = target.y;
  const maxY = minY + target.height;
  const sourceX = sourcePoint.x;
  const targetX = targetPoint.x;
  const minX = target.x;
  const maxX = minX + target.width;
  let newPointX = targetPoint.x;
  let newPointY = targetPoint.y;
  let needUpdate = false;
  console.log(sourceY, targetY, minY, maxY, target);
  if (sourceY !== targetY && sourceY >= minY && sourceY <= maxY) {
    newPointY = sourceY;
    needUpdate = true;
  }
  if (sourceX !== targetX && sourceX >= minX && sourceX <= maxX) {
    newPointX = sourceX;
    needUpdate = true;
  }
  if (needUpdate) {
    const point = new mxPoint(newPointX, newPointY);
    console.log('edge', edge, point,);

    const points = [sourcePoint, point];
    //// const mxGraphView = this.graph.getView();
    //// mxGraphView.updatePoints(edgeState, points, mxGraphView.getState(edge.source), mxGraphView.getState(edge.target));
    //// GraphShapeUtil.updateWaypoints(edge.umlShape, points);
    //// console.log([...mxGraphView.getState(edge).absolutePoints]);
    //// let model = this.graph.getModel();

    //// model.beginUpdate();
    //// try
    //// {
    ////   let geo = model.getGeometry(edge);	
    ////   if (geo != null)
    ////   {
    ////     geo = geo.clone();
    ////     geo.setTerminalPoint(point, false);
    ////     model.setGeometry(edge, geo);
    ////     this.graph.connectCell(edge, edge.target, false, new mxConnectionConstraint());
    ////   }
    //// }
    //// finally
    //// {
    ////   model.endUpdate();
    ////   GraphShapeUtil.updateWaypoints(edge.umlShape, []);
    //// }
    let model = this.graph.getModel();

    model.beginUpdate();
    try {
      console.log('改变端点');

      new mxEdgeHandler(edgeState).changePoints(edge, points);
    } finally {
      model.endUpdate();
    }
  }
  
  //// new mxEdgeHandler(edgeState).changeTerminalPoint(edge, point, false);

};

/**
 * 获取相交线段的point索引值
 * @param {[]} points
 * @return {number}
 */
mxGraphHandler.prototype.getIntersecPointIndex = function (points) {
  let firstPointer = 0;
  const pointsLength = points.length;
  while (firstPointer <= pointsLength - 4) {
    let secondPointer = firstPointer + 2;
    while (secondPointer <= pointsLength - 2) {
      const start1 = [points[firstPointer].x, points[firstPointer].y];
      const end1 = [points[firstPointer + 1].x, points[firstPointer + 1].y];
      const start2 = [points[secondPointer].x, points[secondPointer].y];
      const end2 = [points[secondPointer + 1].x, points[secondPointer + 1].y];
      const Intersection = this.intersection(start1, end1, start2, end2);
      //// console.log('Intersection points', start1, end1, start2, end2);
      //// console.log('Intersection', Intersection);
      if (Intersection.length > 0) {
        return firstPointer;
      }
      secondPointer++;
    }
    firstPointer++;
  }
  return pointsLength - 1;
};

/**
 * 判断两条线段是否相交，不相交返回空数组
 * @param {number[]} start1
 * @param {number[]} end1
 * @param {number[]} start2
 * @param {number[]} end2
 * @return {number[]}
 */
mxGraphHandler.prototype.intersection = function(start1, end1, start2, end2) {
  function getParams(point1, point2) {
    let a;
    let b = 1;
    let c = 0;
    if (point2[0] === point1[0]) {
      return [1, 0, -point2[0]];
    }
    if (point2[1] === point1[1]) {
      return [0, 1, -point2[1]];
    }
    a = (point2[1] - point1[1]) / (point2[0] - point1[0]);
    b = (point2[1] - point1[1]) / (a * (point1[0] - point2[0]));
    c = -a * point1[0] - b * point1[1];
    return [a, b, c];
  }
  const [a1, b1, c1] = getParams(start1, end1);
  const [a2, b2, c2] = getParams(start2, end2);
  //// console.log([a1, b1, c1],[a2, b2, c2])
  let line1Left;
  let line1Right;
  let line1Bottom;
  let line1Top;
  let line2Top;
  let line2Bottom;
  let line2Left;
  let line2Right;
  if (start1[1] <= end1[1]) {
    line1Bottom = start1[1];
    line1Top = end1[1];
  } else {
    line1Bottom = end1[1];
    line1Top = start1[1];   
  }
  if (start1[0] <= end1[0]) {
    line1Left = start1[0];
    line1Right = end1[0];
  } else {
    line1Left = end1[0];
    line1Right = start1[0];   
  }
  if (start2[1] <= end2[1]) {
    line2Bottom = start2[1];
    line2Top = end2[1];
  } else {
    line2Bottom = end2[1];
    line2Top = start2[1];
  }
  if (start2[0] <= end2[0]) {
    line2Left = start2[0];
    line2Right = end2[0];
  } else {
    line2Left = end2[0];
    line2Right = start2[0];   
  }
  if (a1 === a2 && b1 === b2) {
    if (c1 === c2) { //// 同一条直线
      if (start1[0] === end1[0]) { //// 与y轴平行                              
        if (line2Bottom >= line1Bottom && line2Bottom <= line1Top) {
          return [(-line2Bottom * b1 - c1) / a1, line2Bottom];
        } else if (line1Bottom >= line2Bottom && line1Bottom <= line2Top) {
          return [(-line1Bottom * b1 - c1) / a1, line1Bottom];
        } else {
          return [];
        }
      } else {
        if (a1 >= 0) {
          if (line2Left >= line1Left && line2Left <= line1Right) {
            return [line2Left, (-line2Left * a1 - c1) / b1];
          } else if (line1Left >= line2Left && line1Left <= line2Right){
            return [line1Left, (-line2Left * a1 - c1) / b1];
          } else {
            return [];
          }
        } else {
          console.log(line1Left, line1Right, line2Right, line2Left);
          if (line2Right >= line1Left && line2Right <= line1Right) {
            return [line2Right, (-line2Right * a1 - c1) / b1];
          } else if (line1Right >= line2Left && line1Right <= line2Right){
            return [line2Left, (-line2Left * a1 - c1) / b1];
          } else {
            return [];
          }
        }               
      }           
            
    } else { //// 平行线
      return [];
    }
  } else { //// 非平行线
    const x = (c2 * b1 - c1 * b2) / (b2 * a1 - a2 * b1);
    const y = ((c1 * a2 - c2 * a1) / (a1 * b2 - a2 * b1)).toFixed(10);
    if (y >= line1Bottom && y <= line1Top && y >= line2Bottom && y <= line2Top && x >= line1Left && x <= line1Right && x >= line2Left && x <= line2Right) {
      return [x, y];
    } else {
      return [];
    }  
  }
};

/**
     * Updates the hint for the current operation.
     */
mxGraphHandler.prototype.removeHint = function () {
  if (this.hint != null) {
    this.hint.parentNode.removeChild(this.hint);
    this.hint = null;
  }
};

//// Special case for single edge label handle moving in which case the text bounding box is used
let mxGraphHandlerGetBoundingBox = mxGraphHandler.prototype.getBoundingBox;
mxGraphHandler.prototype.getBoundingBox = function (cells) {
  if (cells != null && cells.length == 1) {
    let model = this.graph.getModel();
    let parent = model.getParent(cells[0]);
    let geo = this.graph.getCellGeometry(cells[0]);

    if (model.isEdge(parent) && geo != null && geo.relative) {
      let state = this.graph.view.getState(cells[0]);
      if (
        state != null &&
				state.width < 2 &&
				state.height < 2 &&
				state.text != null &&
				state.text.boundingBox != null
      ) {
        //// return mxRectangle.fromRectangle(state.text.boundingBox);
      }
    }
  }

  return mxGraphHandlerGetBoundingBox.apply(this, arguments);
};
const getCells = mxGraphHandler.prototype.getCells;
mxGraphHandler.prototype.getCells = function (initialCell) {
  let cells = getCells.apply(this, arguments);
  let newCells = [];

  for (let i = 0; i < cells.length; i++) {
    let state = this.graph.view.getState(cells[i]);
    let style =
			state != null ? state.style : this.graph.getCellStyle(cells[i]);

    if (mxUtils.getValue(style, "part", "0") == "1") {
      let parent = this.graph.model.getParent(cells[i]);

      if (
        this.graph.model.isVertex(parent) &&
				mxUtils.indexOf(cells, parent) < 0
      ) {
        newCells.push(parent);
      }
    } else {
      newCells.push(cells[i]);
    }
  }

  return newCells;
};

//// Enables guides
mxGraphHandler.prototype.guidesEnabled = true; //// 显示细胞位置标尺

//// Removes parents where all child cells are moved out
mxGraphHandler.prototype.removeEmptyParents = true;
